/*
 * $Author: isan.wong@gmail.com $
 * $Date: 2011-07-29 01:03:06 +0000 (Fri, 29 Jul 2011) $
 * $Rev: 13 $
 * $URL: http://capitalbio-smd.googlecode.com/svn/src/com/capitalbio/smd/base/StdGene.java $
 */

package com.capitalbio.smd.base;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.biojava.bio.seq.Feature;
import org.biojava.bio.symbol.IllegalSymbolException;
import org.biojava.bio.symbol.Location;
import org.biojava.bio.symbol.SimpleSymbolList;
import org.biojava.bio.symbol.SymbolList;
import org.biojavax.bio.seq.RichSequence;

public class StdGene {
	protected Log log = LogFactory.getLog(this.getClass());
	
	private RichSequence sequence;
	private SymbolList symbolList;
	private List<int[]> exonRegions;
	private List<int[]> ivsRegions;
	private List<int[]> cdsRegions;
	
	private SymbolList cds;
	
	private List<int[]> concernedRegions;
	private List<Variation> commonVariations;

	private String name;
	private String label;

	public StdGene(RichSequence richSequence, Properties properties) {
		this.sequence = richSequence;

		//Concerned region
		String concernsStr = properties.getProperty("smd.alignment.gene.concerned.regions");
		if (concernsStr != null && !concernsStr.equals("")) {
			concernedRegions = Util.processRegionProperty(concernsStr);
		}
		else {
			concernedRegions = new ArrayList<int[]>();
			concernedRegions.add(new int[] {1, sequence.length()});
		}
		
		//Common variations
		commonVariations = new ArrayList<Variation>();
		String variationsStr = properties.getProperty("smd.alignment.gene.variations");
		if (variationsStr != null && !variationsStr.equals("")) {
			String[] variationStrs = variationsStr.split(",");
			
			for (int i = 0; i < variationStrs.length; i++) {
				try {
					Variation variation = Variation.parseVariation(variationStrs[i]);
					commonVariations.add(variation);
					
				} catch (IllegalSymbolException e) {
					log.error(e);
				}
			}
		}
		
		//Label
		String uniqueName = properties.getProperty("smd.glignment.gene.name.unique");
		String commonName = properties.getProperty("smd.glignment.gene.name.common");
		name = uniqueName;
		if (commonName != null) {
			label = uniqueName + " (" + commonName + ")";
		}
		else {
			label = uniqueName;	
		}
		
		cdsRegions = getRegions("CDS");
		exonRegions = getRegions("exon");
		
		//log.debug(getCds().seqString().toUpperCase());
	}
	
	/**
	 * get combined CDS sequence
	 * @return combined CDS sequence, as SybmolList
	 */
	public SymbolList getCds() {
		if (cds == null) {
			StringBuilder cdsBuilder = new StringBuilder();
			for (int[] cdsRegion : cdsRegions) {
				cdsBuilder.append(sequence.subList(cdsRegion[0], cdsRegion[1]).seqString());
			}
			try {
				cds = new SimpleSymbolList(Util.getDNATokenization(), cdsBuilder.toString());
			} catch (IllegalSymbolException e) {
				log.error(e);
			}
		}
		return cds;
	}
	
	public RichSequence getSequence() {
		return sequence;
	}
	
	/**
	 * 返回关心的区域连接起来的的符号列表
	 * @return 关心的区域的符号列表
	 */
	public SymbolList getSymbolList() {
		if (symbolList == null) {
			StringBuilder concerndBuilder = new StringBuilder();
			for (int[] concernedRegion : concernedRegions) {
				concerndBuilder.append(sequence.subList(concernedRegion[0], concernedRegion[1]).seqString());
			}
			try {
				symbolList = new SimpleSymbolList(Util.getDNATokenization(), concerndBuilder.toString());
			} catch (IllegalSymbolException e) {
				log.error(e);
			}
		}

		return symbolList;
	}

	/**
	 * Exon regions
	 * @return Exon region list
	 */
	public List<int[]> getExonRegions() {
		return exonRegions;
	}

	/**
	 * CDS region list
	 * @return CDS region list
	 */
	public List<int[]> getCdsRegions() {
		return cdsRegions;
	}

	/**
	 * IVS regions
	 * @return IVS region list
	 */
	public List<int[]> getIvsRegions() {
		return ivsRegions;
	}

	private List<int[]> getRegions(String featureType) {
		Set<Feature> stdSeqFeatures = sequence.getFeatureSet();
		List<int[]> locations = new ArrayList<int[]>();
		for (Iterator<Feature> it = stdSeqFeatures.iterator(); it.hasNext();) {
			Feature feature = (Feature) it.next();
			if (feature.getType().equals(featureType)) {
				Location location = feature.getLocation();
				if (location.isContiguous()) {
					locations.add(new int[] {location.getMin(), location.getMax()});
				}
				else {
					@SuppressWarnings("rawtypes")
					Iterator blockIterator = location.blockIterator();
					while (blockIterator.hasNext()) {
						Location block = (Location) blockIterator.next();
						locations.add(new int[] {block.getMin(), block.getMax()});
					}
				}
			}
		}
		return locations;
	}

	public List<int[]> getConcernedRegions() {
		return concernedRegions;
	}

	/**
	 * Common variations of the gene
	 * @return variations list
	 */
	public List<Variation> getCommonVariations() {
		return commonVariations;
	}
	
	/**
	 * Common variations of the gene
	 * @return variations list
	 */
	public List<Variation> getCommonVariations(VariationType type) {
		List<Variation> variations = new ArrayList<Variation>();
		for (Variation variation : commonVariations) {
			if (variation.getType() == type) {
				variations.add(variation);
			}
		}
		return variations;
	}
	
	/**
	 * unique gene name
	 * @return gene name
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * gene label like SLC26A4 (PDS)
	 * @return gene label
	 */
	public String toString() {
		return label;
	}

}
